import processing.core.*;

// Library for the GUI taken from http://www.sojamo.de/libraries/controlP5/
import controlP5.*;
// Library for the OSC protocol taken from http://www.sojamo.de/libraries/oscP5/
import oscP5.*;

import processing.serial.*;
import netP5.*;

public class Sketch extends PApplet {
	
private static final long serialVersionUID = 327967096600687174L ;

	ControlP5 cp5 ;
	ListBox l ;
	Toggle t ;
	boolean toggleValue=false ; 
	String[] list_port ;
	Serial myPort ;
	
// 	Array used to disable the log message of the device sent by serial protocol	
	String[] tab = new String[2];

// Creating the variable needed for the OSC protocol
	  OscP5 X ;
	  OscP5 Y ;
	  OscP5 Z ;
	  OscP5 Pitch ;
	  OscP5 Yaw ;
	  OscP5 Roll ;
	  
	  NetAddress myRemoteLocation_X ;
	  NetAddress myRemoteLocation_Y ;
	  NetAddress myRemoteLocation_Z ;
	  NetAddress myRemoteLocation_Pitch ;
	  NetAddress myRemoteLocation_Yaw ;
	  NetAddress myRemoteLocation_Roll;

	  OscMessage message_X ;
	  OscMessage message_Y ;
	  OscMessage message_Z ;
	  OscMessage message_Pitch ;
	  OscMessage message_Yaw ;
	  OscMessage message_Roll ;
	  	
	  
// Creating a token to increment only once after the opening of the ports for the OSC protocol using the toggle 
	  int token = 0 ;
	  
// Function used to receive the string set by the Bluetooth device	  
	  String[] setup_serial() {
			
		int i ;
	       i= 0 ;
	  while (i < 2) {
	      tab[i] = myPort.readStringUntil('\n') ; 
	  while (tab[i] == null){         
	     delay(1) ;
	       tab[i]= myPort.readStringUntil('\n') ;        
	      } 
	    i = i + 1 ;
	  }
	
	return tab ;

	}		

// Function used for parsing to float the string sent by Bluetooth	  
		public float[] parse_serial(){
			
			 String[] tampon = setup_serial() ;	

// Array used  for splitting the string sent by serial			 
		     String[] split_inBuffer = tampon[1].split("\\;\\s") ;	     		
			 float serial[] = new float[split_inBuffer.length] ;
			
// Float are rounder by 2 numbers after the dot			
				serial[0]= Math.round(Double.valueOf(split_inBuffer[0]).doubleValue()*100.0/100.0) ;
				serial[1]= Math.round(Double.valueOf(split_inBuffer[1]).doubleValue()*100.0/100.0) ;
				serial[2]= Math.round(Double.valueOf(split_inBuffer[2]).doubleValue()*100.0/100.0) ;
				serial[3]= Math.round(Double.valueOf(split_inBuffer[3]).doubleValue()*100.0/100.0) ;
				serial[4]= Math.round(Double.valueOf(split_inBuffer[4]).doubleValue()*100.0/100.0) ;
				serial[5]= Math.round(Double.valueOf(split_inBuffer[5]).doubleValue()*100.0/100.0) ;
			    return serial  ;
		}
		  
// This void update the data displayed on the GUI		
		  void update_GUI(float serial[]){
		 		
				cp5.getController("X").setValue(serial[0]) ;
				cp5.getController("Y").setValue(serial[1]) ;
				cp5.getController("Z").setValue(serial[2]) ;
				cp5.getController("Pitch").setValue(serial[3]) ;
				cp5.getController("Yaw").setValue(serial[4]) ;
				cp5.getController("Roll").setValue(serial[5]) ;		
			    cp5.getController("Pitch").setValue(serial[3]) ;	  
		  }
	
// This void is used to open the UDP port that have been chosen by the user in the GUI		  
			 void set_UDP() {    
			       
			       while( token == 0) 
			       {
			    	
// The "If" only checks the Textfields that are not empty				    	   
			         if(cp5.get(Textfield.class,"UDP_X").getText().isEmpty()!= true) {
			        	 	        	
			        	int signal_X= Integer.parseInt(cp5.get(Textfield.class,"UDP_X").getText());
			            X= new OscP5(this,signal_X) ;
			            myRemoteLocation_X = new NetAddress("127.0.0.1",signal_X) ;
			             }
			         
			         if (cp5.get(Textfield.class,"UDP_Y").getText().isEmpty()!= true) {
			        	 int signal_Y=Integer.parseInt(cp5.get(Textfield.class,"UDP_Y").getText());
			         Y= new OscP5(this,signal_Y) ;
			         myRemoteLocation_Y = new NetAddress("127.0.0.1",signal_Y) ;
			         
			    }
			         if(cp5.get(Textfield.class,"UDP_Z").getText().isEmpty()!= true) {
			        	 int signal_Z=Integer.parseInt(cp5.get(Textfield.class,"UDP_Z").getText());
			         Z= new OscP5(this,signal_Z) ;
			         myRemoteLocation_Z = new NetAddress("127.0.0.1",signal_Z) ;
			         
			    }
			         if(cp5.get(Textfield.class,"UDP_Pitch").getText().isEmpty()!= true) {
			        	 int signal_Pitch=Integer.parseInt(cp5.get(Textfield.class,"UDP_Pitch").getText()) ;
			         Pitch= new OscP5(this,signal_Pitch);
			         myRemoteLocation_Pitch = new NetAddress("127.0.0.1",signal_Pitch) ;
			         
			    }
			         if(cp5.get(Textfield.class,"UDP_Yaw").getText().isEmpty()!= true) {
			        	 int signal_Yaw=Integer.parseInt(cp5.get(Textfield.class,"UDP_Yaw").getText()) ;
			         Yaw= new OscP5(this,signal_Yaw);
			         myRemoteLocation_Yaw  = new NetAddress("127.0.0.1",signal_Yaw) ;
			         
			    }
			         if(cp5.get(Textfield.class,"UDP_Roll").getText().isEmpty()!= true) {
			        	 int signal_Roll=Integer.parseInt(cp5.get(Textfield.class,"UDP_Roll").getText()) ;
			         Roll= new OscP5(this,signal_Roll) ;
			         myRemoteLocation_Roll = new NetAddress("127.0.0.1",signal_Roll) ;
			         
			    }
			      token = token + 1 ;
			       }    
			  }
			 
// This void sends the Bluetooth string (parsed to float by parse_serial() function)  via the OSC protocol				 
			  void UDP_message(){
				    				  
				  float[] tab = parse_serial() ;
							               		       
			         if(cp5.get(Textfield.class,"UDP_X").getText().isEmpty()!= true) {
			            message_X = new OscMessage(""+tab[0]) ;
			            X.send(message_X,myRemoteLocation_X);
			    }
			         if(cp5.get(Textfield.class,"UDP_Y").getText().isEmpty()!= true) {
			        	 message_Y = new  OscMessage(""+tab[1]) ;
			            Y.send(message_Y,myRemoteLocation_Y) ;
			    }
			         if(cp5.get(Textfield.class,"UDP_Z").getText().isEmpty()!= true) {
			        	  message_Z = new  OscMessage(""+tab[2]) ;
			              Z.send(message_Z,myRemoteLocation_Z) ;
			    }
			         if(cp5.get(Textfield.class,"UDP_Pitch").getText().isEmpty()!= true) {
			        	 message_Pitch = new  OscMessage(""+tab[3]) ;
			         Pitch.send(message_Pitch,myRemoteLocation_Pitch) ;
			    }
			         if(cp5.get(Textfield.class,"UDP_Yaw").getText().isEmpty()!= true) {
			        	 message_Yaw = new  OscMessage(""+tab[4]) ;
			          Yaw.send(message_Yaw,myRemoteLocation_Yaw) ;
			    }
			         if(cp5.get(Textfield.class,"UDP_Roll").getText().isEmpty()!= true) {
			        	 message_Roll = new  OscMessage(""+tab[5]) ;
			        Roll.send(message_Roll,myRemoteLocation_Roll) ;
			    }
			         update_GUI(tab) ;
			       
			  }
			  
				
// This void activates the whole procedure to send the data through the OSC procedure	
	          void toggle(){
		
	if(toggleValue == false){
		  t.captionLabel().set("OSC on") ;
		    background(255) ;
		    set_UDP() ;
	        UDP_message() ;    
	}
	
	else {
		  t.captionLabel().set("OSC off") ;
		  background(255) ;
		  
		  myPort.clear() ;
		  token = 0 ;
		  
		  float[] tab = parse_serial() ;
		  update_GUI(tab) ;
	}
	}
	  
	public void setup() {
		
// List all the available serial ports:				  
		  while (Serial.list().length ==  0) {
			    delay (100) ;
			  }
// Open the serial port you are using at the rate you want:			 		  
		  myPort = new Serial(this, Serial.list()[0], 115200) ;					  		  
		  myPort.clear() ;
		  		
		  size(800, 600) ;
		  smooth() ;
		  
		  cp5 = new ControlP5(this) ;
		 
// Toggle
    t = cp5.addToggle("toggleValue")
		   .setPosition(10,40)
		   .setSize(20,10)
		   .setColorBackground(color(210))
		   .setColorActive(color(255,0,0))
		   .setValue(true)
		   .setMode(ControlP5.SWITCH)
		   ;
		  t.captionLabel().toUpperCase(true);
		  t.captionLabel().setColor(color(0));
		  t.captionLabel().style().marginLeft = 28;
		  t.captionLabel().style().marginTop = -12;
		  
		 
		

		  //slider Acceleration x
	   cp5.addSlider("X")
	      .setPosition(10,100)
	      .setSize(200,50)
	      .setColorBackground(color(210)) 
	      .setColorForeground(color(255,0,0))
	      .setColorActive(color(255,0,0))
	      .setColorLabel(color(0))
	      .setRange(-255,255)
	      ;
	      
//Textfield meant to be filled in order to choose the port where you want our data to be sent for X axis	      
	  cp5.addTextfield("UDP_X")
	     .setPosition(250,100)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;     
	      
//slider Acceleration y
	  cp5.addSlider("Y")
	     .setPosition(10,300)
	     .setSize(200,50)
	     .setColorBackground(color(210)) 
	     .setColorForeground(color(255,0,0))
	     .setColorActive(color(255,0,0))
	     .setColorLabel(color(0))
	     .setRange(-255,255)
	     ;   
	         
//Textfield meant to be filled in order to choose the port where you want our data to be sent for Y axis
	  cp5.addTextfield("UDP_Y")
	     .setPosition(250,300)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;    
	      
//slider Acceleration z
	  cp5.addSlider("Z")
	     .setPosition(10,500)
	     .setSize(200,50)
	     .setColorBackground(color(210)) 
	     .setColorForeground(color(255,0,0))
	     .setColorActive(color(255,0,0))
	     .setColorLabel(color(0))
	     .setRange(-255,255)
	     ; 
	      
//Textfield meant to be filled in order to choose the port where you want our data to be sent for Z axis
	  cp5.addTextfield("UDP_Z")
	     .setPosition(250,500)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;
	  
//slider Rotation pitch
	  cp5.addSlider("Pitch")
	     .setPosition(400,100)
	     .setSize(200,50)
	     .setColorBackground(color(210)) 
	     .setColorForeground(color(255,0,0))
	     .setColorActive(color(255,0,0))
	     .setColorLabel(color(0))
	     .setRange(-180,180)
	     ; 
	       
	  cp5.addTextfield("UDP_Pitch")
	     .setPosition(650,100)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;    
	  
//slider Rotation yaw
	  cp5.addSlider("Yaw")
	     .setPosition(400,300)
	     .setSize(200,50)
	     .setColorBackground(color(210)) 
	     .setColorForeground(color(255,0,0))
	     .setColorActive(color(255,0,0))
	     .setColorLabel(color(0))
	     .setRange(-180,180)
	     ;   
	         
	  cp5.addTextfield("UDP_Yaw")
	     .setPosition(650,300)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;    
	      
	      //slider Rotation roll
	  cp5.addSlider("Roll")
	     .setPosition(400,500)
	     .setSize(200,50)
	     .setColorBackground(color(210)) 
	     .setColorForeground(color(255,0,0))
	     .setColorActive(color(255,0,0))
	     .setColorLabel(color(0))
	     .setRange(-180,180)
	     ;   
	          
	  cp5.addTextfield("UDP_Roll")
	     .setPosition(650,500)
	     .setSize(50,50)
	     .setFocus(true)
	     .setColor(color(255,0,0))
	     .setColorBackground(color(210)) 
	     ;      
	           		     
  l = cp5.addListBox("myList")
		  .setPosition(10, 30)
		  .setSize(120, 50)
		  .close()
		  .setItemHeight(15)
		  .setBarHeight(15)
		  .setColorBackground(color(40, 128))
		  .setColorActive(color(255, 128))
		  ;

		 l.captionLabel().toUpperCase(true);
		 l.captionLabel().set("Port Serie");
		 l.captionLabel().setColor(0xffff0000);
		 l.captionLabel().style().marginTop = 3;
		 l.valueLabel().style().marginTop = 3;
		  
		
// Used to give the list of all the available serial ports		  
		  int i=0;
		  list_port= Serial.list();
		  while(i< list_port.length) {
		    ListBoxItem lbi = l.addItem(list_port[i],i);
		    lbi.setColorBackground(0xffff0000);
		    i=i+1;
		  }
	}

	
	public void draw() {		  		
			delay(20) ;		   
			toggle() ;		
	}
	
	
	public static void main(String args[]) {
		PApplet.main(new String[] { "--present", "Sketch" }) ;
	}
}